package edu.uw.tcss360.group6.model;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
/**
 * Project: cd1 phase
 * Group 6- Ambi Adla
 * Author: David Sharer
 * Author: Bill Minter
 * Date: 2/24/13
 */

@SuppressWarnings("serial")
public class Contest implements java.io.Serializable {

    private Organizer organizer;  //BR19: For each event there is only one user who is the organizer

	private ArrayList<Category> my_categories;

    private HashMap<String,Entry> my_entries; //TODO: Is this really where we want entry data? -David

    private HashMap<String,User> my_users;

    private Contest() {
        my_categories = new ArrayList<Category>();
        my_entries = new HashMap<String,Entry>();
        my_users = new HashMap<String,User>();
    }
	
	//for the createUser method, why not just use regular object declaration?
	//Are we creating a collection of users within the edu.uw.tcss360.group6.model.Contest class?

    public User[] getUsers() {
        return my_users.values().toArray(new User[my_users.values().size()]);
    }

    public Category[] getCategories() {
        return my_categories.toArray(new Category[my_categories.size()]);
    }

    public Entry[] getEntries() {
        return my_entries.values().toArray(new Entry[my_entries.values().size()]);
    }

    public User addUser(User user) {
        if(user == null)
            throw new IllegalArgumentException("user not permitted to be null");
        if(my_users.containsKey(user.getUsername()))
            throw new IllegalArgumentException("edu.uw.tcss360.group6.model.User already exists.");
        my_users.put(user.getUsername(), user);
        return user;
    }

    /**
     * @param category The category to add.
     * @throws IllegalArgumentException if category is null
     */
    public void addCategory(Category category) {
        if(category == null)
            throw new IllegalArgumentException("category not permitted to be null");
        my_categories.add(category);
    }

    /**
     * Promote or edit a user.
     * @param user The user to edit
     * @param newUser The new state of the user.
     * @throws IllegalArgumentException if the new user does not have the same username as the old user
     * @throws IllegalArgumentException if either user is null
     * @return the updated user
     */
    public User updateUser(User user, User newUser) {
        //TODO: UPDATE EXCEPTION
        if(user == null || newUser == null)
            throw new IllegalArgumentException("user and newUser not permitted to be null");
        if(!user.getUsername().equals(newUser.getUsername()))
            throw new IllegalArgumentException("Old Username must be the same as the new Username.");

        my_users.put(user.getUsername(), newUser);

        return newUser;
    }

    /**
     * Promote a user to edu.uw.tcss360.group6.model.Contestant status
     * @param user user to promote
     * @throws IllegalArgumentException if user is null or user is not a edu.uw.tcss360.group6.model.User.
     */
    public Contestant userToContestant(User user) {
        //TODO: UPDATE EXCEPTION
        if(user == null)
            throw new IllegalArgumentException("user and newUser not permitted to be null");
        if(user.getClass().equals(Contestant.class))
            return (Contestant)user;
        if(!user.getClass().equals(User.class))
            throw new IllegalArgumentException("user is not a Attendee. Cannot promote");

        Contestant c = new Contestant(user);
        my_users.put(user.getUsername(), c);

        return c;
    }

    /** Retreives a users data based off username.
     * @param username the entered username
     * @return The user.
     */
    public User getUser(String username){
        //TODO: username exception
        if(my_users.containsKey(username))
            return my_users.get(username);
        return null;
    }

    /**
     * Add an entry to the contest.
     * @param proposedEntry The proposed entry
     */
    public void addEntry(Entry proposedEntry) {
        Contestant c = proposedEntry.getContestant();
        if(c.getNumberOfEntries() < 3) {
            proposedEntry.getContestant().associateEntry(proposedEntry);
            proposedEntry.getCategory().addEntry(proposedEntry);
            my_entries.put(proposedEntry.getID(), proposedEntry);
        }//TODO: Throw exception
    }
    //singleton junk
    /** The location of the contest save data. **/
    private static final String FILENAME = "contest.ser";

    /** edu.uw.tcss360.group6.model.Contest is a singleton. This is it. **/
    private static Contest the_only_contest = null;

    /**
     * @return The only instance of contest you'll ever get.
     */
    public static Contest instance() {
        if(the_only_contest == null)
            the_only_contest = load();
        return the_only_contest;
    }

    /**
     * @return contest loaded from file, or generated contest (if file does not exist);
     */
    private static Contest load() {
        try {
            Contest contest;
            FileInputStream fis = new FileInputStream(FILENAME);
            ObjectInputStream ois = new ObjectInputStream(fis);
            contest = (Contest) ois.readObject();
            ois.close();
            return contest;
        } catch (Exception ex) {
            return generate();
        }
    }

    /**
     * Reloads the contest from file.
     * @return reloaded contest
     */
    public static Contest reload() {
        return the_only_contest = load();
    }

    /**
     * Generates a "contest" for testing.
     * @return generated contest.
     */
    private static Contest generate() {
        Contest contest = new Contest();

        ///contests
        contest.addCategory(new Category("Batman"));
        contest.addCategory(new Category("Superman"));
        contest.addCategory(new Category("Wonder Woman"));
        contest.addCategory(new Category("Flash"));
        contest.addCategory(new Category("Green Lantern"));
        contest.addCategory(new Category("Aquaman"));
        contest.addCategory(new Category("Martian Manhunter"));

        ///users
        //organizer
        contest.organizer = new Organizer(new User("organizer","Organ I. Zer", "867-5309", "Address","email"));
        contest.addUser(contest.organizer);
        //attendees

        //contestants

        contest.addUser(new User("contestant1","Cont E. Stant", "867-5309", "Address","email"));

        //judges
        //...

        return contest;
    }
    public Category getCategory(String category_name)
    {
    	
    	Category[] category_array = getCategories();
    	for(int i = 0; i < category_array.length;i++)
    	{
    		if(category_array[i].getName() == category_name)
    		{
    			return category_array[i];
    		}
    	}
    	return null;
    }

    public static void save() throws IOException {
        try {
            FileOutputStream fos = new FileOutputStream(FILENAME);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(Contest.instance());
            oos.close();
        } catch (Exception ex) {
            throw new IOException("Could not save.");
        }
    }
}
